#include <iostream>
#include <vector>

using namespace std;

class Obj{
public:
    int *x;
};

void TEST1(){
    // 左值与右值的区别，左值引用只能绑定左值，右值引用只能绑定右值，const引用都可以绑定

    int i = 42;
    int &r = i;
    // int &&rr = i; //不能将右值引用绑定到左值上
    // int &r2 = i * 42; //不能将左值引用绑定到右值上
    int &&rr2 = i * 42;
    const int &r3 = i * 42; //左值和右值都可以绑定到const引用上
    
    // 同上
    Obj a;
    Obj &ra = a;
    // Obj &&rra = a;
    //Obj &ra2 = Obj();
    Obj &&rra2 = Obj();
    const Obj& ra3 = Obj();
}

int f(){
    return 0;
}

void TEST2(){
    // C++ Primer 练习13.46
    vector<int> vi(100);
    int&& r1 = f(); // 函数返回的非引用类型是右值
    int&  r2 = vi[0]; // 容器内的元素是左值
    int&  r3 = r1; // 变量是左值
    int&& r4 = vi[0] * f(); // 临时对象是右值
}

// A只定义了拷贝构造和拷贝赋值
class A{
public:
    A() = default;
    A(const A& a){ cout << __PRETTY_FUNCTION__ << endl; }
    A& operator=(const A& a){ cout << __PRETTY_FUNCTION__ << endl; }
};

// B还定义了移动构造和移动复制
class B{
public:
    B() = default;
    B(const B& a){ cout << __PRETTY_FUNCTION__ << endl; }
    B& operator=(const B& a){ cout << __PRETTY_FUNCTION__ << endl; }
    B(B&& a) noexcept { cout << __PRETTY_FUNCTION__ << endl; }
    B& operator=(B&& a) noexcept {cout << __PRETTY_FUNCTION__ << endl; }
};

void  TEST3(){
    // C++ Primer 练习13.48
    vector<A> vA;
    A a;
    cout << "每次push_back都会调用拷贝构造函数，而且由于vector的内存分配机制，每当长度达到2^n + 1时，就需要拷贝整个vector" << endl;
    // 重分配内存时，调用拷贝构造函数
    for (int i=0; i<12; ++i){
        printf("------------- %d -------------\n", i+1);
        vA.push_back(a); // 调用拷贝构造函数
    }
    cout << endl;

    vector<B> vB;
    B b;
    cout << "一旦对象有了noexcept的移动构造函数，vector在重分配内存的时候就会默认使用移动构造函数" << endl;
    // 重分配内存时，调用移动构造函数
    for (int i=0; i<12; ++i){
        printf("------------- %d -------------\n", i+1);
        vB.push_back(b); // 调用拷贝构造函数
    }
    cout << endl;

    vB.push_back(std::move(b)); // 调用移动构造函数
    vB[0] = b; // 调用拷贝赋值函数
    vB[0] = std::move(b); // 调用移动赋值函数
}

int main(){
    TEST1();
    TEST2();
    TEST3();
    return 0;
}
